package cn.zl.GB28181.session;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.zl.GB28181.core.SipTransactionInfo;
import cn.zl.GB28181.core.SsrcTransaction;
import cn.zl.common.InviteSessionType;
import cn.yunbamboos.exception.AppException;
import gov.nist.javax.sip.message.SIPResponse;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 视频流session管理器，管理视频预览、预览回放的通信句柄
 */
@Component
public class VideoStreamSessionManager {

    private final Map<String, VideoStreamSession> cache = new ConcurrentHashMap<>();


    /**
     * 添加一个点播/回放的事务信息
     * 后续可以通过流Id/callID
     *
     * @param deviceId  设备编号
     * @param channelId 通道编号
     * @param callId    一次请求的CallID
     * @param stream    流名称
     * @param response  回复
     */
    public void put(String deviceId, String channelId, String callId, String stream, String ssrc, SIPResponse response, InviteSessionType type) {
        VideoStreamSession session = new VideoStreamSession();
        session.deviceId = deviceId;
        session.channelId = channelId;
        session.callId = callId;
        session.stream = stream;
        String key = session.getKey();
        if (cache.containsKey(key)) {
            throw AppException.c("已存在视频流session");
        }
        session.transaction = new SsrcTransaction();
        session.transaction.setDeviceId(deviceId);
        session.transaction.setChannelId(channelId);
        session.transaction.setStream(stream);
        session.transaction.setSipTransactionInfo(new SipTransactionInfo(response));
        session.transaction.setCallId(callId);
        session.transaction.setSsrc(ssrc);
        session.transaction.setType(type);
        cache.put(key, session);
    }

    public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream) {
        for (Map.Entry<String, VideoStreamSession> entry : cache.entrySet()) {
            VideoStreamSession session = entry.getValue();
            if (session.checkDeviceId(deviceId) && session.checkChannelId(channelId) && session.checkCallId(callId) && session.checkStream(stream)) {
                return session.transaction;
            }
        }
        return null;
    }

    public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream) {
        List<SsrcTransaction> transactions = new ArrayList<>();
        for (Map.Entry<String, VideoStreamSession> entry : cache.entrySet()) {
            VideoStreamSession session = entry.getValue();
            if (session.checkDeviceId(deviceId) && session.checkChannelId(channelId) && session.checkCallId(callId) && session.checkStream(stream)) {
                transactions.add(session.transaction);
            }
        }
        return transactions;
    }

    public String getSSRC(String deviceId, String channelId, String stream) {
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
        if (ssrcTransaction == null) {
            return null;
        }
        return ssrcTransaction.getSsrc();
    }

    public void remove(String deviceId, String channelId, String stream) {
        List<SsrcTransaction> ssrcTransactionList = getSsrcTransactionForAll(deviceId, channelId, null, stream);
        if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) {
            return;
        }
        for (SsrcTransaction ssrcTransaction : ssrcTransactionList) {
            cache.remove(deviceId + ":" + channelId + ":" + ssrcTransaction.getCallId() + ":" + ssrcTransaction.getStream());
        }
    }

    public void removeByCallId(String deviceId, String channelId, String callId) {
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null);
        if (ssrcTransaction == null) {
            return;
        }
        cache.remove(deviceId + ":" + channelId + ":" + ssrcTransaction.getCallId() + ":" + ssrcTransaction.getStream());
    }

    private VideoStreamSession getSession(String deviceId, String channelId) {
        String key = deviceId + "_" + channelId;
        VideoStreamSession session = cache.get(key);
        if (ObjUtil.isNull(session)) {
            return null;
        }
        return session;
    }

    public static class VideoStreamSession {

        String deviceId;
        String channelId;
        String callId;
        String stream;
        SsrcTransaction transaction;

        /**
         * deviceId:channelId:callId:stream
         */
        String getKey() {
            return StrUtil.format("{}:{}:{}:{}", deviceId, channelId, callId, stream);
        }

        boolean checkDeviceId(String deviceId) {
            if (ObjUtil.isNull(deviceId)) {
                return true;
            }
            return this.deviceId.equals(deviceId);
        }

        boolean checkChannelId(String channelId) {
            if (ObjUtil.isNull(channelId)) {
                return true;
            }
            return this.channelId.equals(channelId);
        }

        boolean checkCallId(String callId) {
            if (ObjUtil.isNull(callId)) {
                return true;
            }
            return this.callId.equals(callId);
        }

        boolean checkStream(String stream) {
            if (ObjUtil.isNull(stream)) {
                return true;
            }
            return this.stream.equals(stream);
        }


    }
}
